﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace System.Windows.Data
{
    public class ValidateBinding
    {
        private static string _propertyName = string.Empty;
        public static readonly DependencyProperty ValidatesOnDataErrorsProperty =
            DependencyProperty.RegisterAttached("ValidatesOnDataErrors",
                typeof(bool),
                typeof(ValidateBinding),
                new PropertyMetadata(true, ValidatesOnDataErrorsChanged));

        public static readonly DependencyProperty PropertyNameProperty =
            DependencyProperty.RegisterAttached("PropertyName",
                typeof(string),
                typeof(ValidateBinding),
                new PropertyMetadata(string.Empty, PropertyNameChanged));

        private static readonly DependencyProperty ContextProperty =
            DependencyProperty.RegisterAttached("Context",
                typeof(object),
                typeof(ValidateBinding),
                new PropertyMetadata(ContextChanged));

        private static void ContextChanged(
            DependencyObject obj,
            DependencyPropertyChangedEventArgs args)
        {
            INotifyPropertyChanged prop = args.OldValue as INotifyPropertyChanged;
            if (prop != null)
            {
                prop.PropertyChanged -= new PropertyChangedEventHandler(prop_PropertyChanged);
            }
            prop = args.NewValue as INotifyPropertyChanged;
            if (prop != null)
            {
                prop.PropertyChanged += new PropertyChangedEventHandler(prop_PropertyChanged);
            }
            Validate(args.NewValue);
        }

        /// <summary>
        /// The property changed callback for <see cref="PropertyNameProperty"/>.
        /// </summary>
        private static void PropertyNameChanged(
            DependencyObject obj,
            DependencyPropertyChangedEventArgs args)
        {
            string propertyName = args.NewValue.ToString();
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new ArgumentNullException("PropertyName");
            }
            _propertyName = propertyName;
        }

        /// <summary>
        /// The property changed callback for <see cref="ValidatesOnDataErrorsProperty"/>.
        /// </summary>
        private static void ValidatesOnDataErrorsChanged(
            DependencyObject obj,
            DependencyPropertyChangedEventArgs args)
        {
            FrameworkElement el = obj as FrameworkElement;
            if ((bool)args.NewValue)
            {
                el.SetBinding(ContextProperty, new Binding());
            }
            else
            {
                el.SetBinding(ContextProperty, null);
            }
        }

        static void prop_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == _propertyName)
            {
                Validate(sender);
            }
        }

        private static void Validate(object sender)
        {
            IDataErrorInfo info = sender as IDataErrorInfo;
            if (info != null)
            {
                string errorText = info[_propertyName];
                if (string.IsNullOrEmpty(errorText))
                {
                }
                else
                {
                }
                ToolTipService.SetToolTip(sender as DependencyObject, errorText);
            }
        }

        /// <summary>
        /// Work our way back up the visual tree looking for the data context.
        /// </summary>
        /// <param name="obj">The dependency object that we are going to check
        /// to see if it has a DataContext.</param>
        /// <returns>The DataContext if available, otherwise null.</returns>
        private static object GetContext(DependencyObject obj)
        {
            FrameworkElement el = obj as FrameworkElement;
            if (el != null)
            {
                if (el.DataContext == null)
                {
                    DependencyObject parent = VisualTreeHelper.GetParent(obj);
                    if (parent != null)
                    {
                        return GetContext(parent);
                    }
                }
                else
                {
                    return el.DataContext;
                }
            }
            return null;
        }
    }
}
